#include "ComponentFishOutOfWaterBehavior.h"
#include "Components/ComponentCreature.h"
#include "Components/ComponentBody.h"
#include "Components/ComponentCreatureSounds.h"
#include "Components/ComponentLocomotion.h"
#include "ComponentPathfinding.h"
#include "Subsystems/SubsystemTerrain.h"
#include "Subsystems/SubsystemTimeOfDay.h"
#include "GameRandom.hpp"
#include "Engine/MathUtils.hpp"
#include "Log.h"
#include "Terrain/ScSimplexNoise.h"

#include "GameSingleton.h"
#include "GameRegistry.hpp"
#include "GameThreadPool.hpp"

#include <iostream>

namespace PocketSurvival
{

    // ************** 【状态机】 **************

    ComponentFishOutOfWaterBehavior::StateMachine::StateMachine(ComponentFishOutOfWaterBehavior *fishOutOfWater) : m_fishOutOfWater(fishOutOfWater), EasyMachine(MachineState::Inactive) {}

    void ComponentFishOutOfWaterBehavior::StateMachine::enter()
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            break;
        case MachineState::Jump:
            m_fishOutOfWater->setIsBend(true);
            break;
        }
    }

    void ComponentFishOutOfWaterBehavior::StateMachine::update(float dt)
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            MACHINE_DELEGATE()
            {
                if (m_fishOutOfWater->isOutOfWater())
                {
                    m_fishOutOfWater->m_outOfWaterTime += dt;
                }
                else
                {
                    m_fishOutOfWater->m_outOfWaterTime = 0.0f;
                }
                if (m_fishOutOfWater->m_outOfWaterTime > 3.0f)
                {
                    m_fishOutOfWater->m_importanceLevel = 1000.0f;
                }
                if (m_fishOutOfWater->isActive())
                {
                    changeTo(MachineState::Jump);
                }
            }
            break;
        case MachineState::Jump:
            MACHINE_DELEGATE()
            {
                float bendOrder = 2.0f * (2.0f * MathUtils::Saturate(
                    ScSimplexNoise::OctavedNoise(
                        (float)MathUtils::Remainder(m_fishOutOfWater->subsystemTimeOfDay->getGameTime(), 1000.0), 1.2f * m_fishOutOfWater->componentCreature->componentLocomotion->turnSpeed, 1, 1.0f, 1.0f )) - 1.0f);
                
                if (!m_fishOutOfWater->isActive())
                {
                    changeTo(MachineState::Inactive);
                }
                if (!m_fishOutOfWater->isOutOfWater())
                {
                    m_fishOutOfWater->m_importanceLevel = 0.0f;
                }
                if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 2.5f * dt)
                {
                    m_fishOutOfWater->componentCreature->componentLocomotion->setJumpOrder(GameSingleton::gameRandom->getFloat(0.33f, 1.0f));
                    m_fishOutOfWater->m_direction = Vector2(MathUtils::Sign(bendOrder), 0.0f);
                }
                if (m_fishOutOfWater->componentCreature->componentBody->standingOnValue != 0)
                {
                    m_fishOutOfWater->componentCreature->componentLocomotion->setTurnOrder(Vector2(0.0f - bendOrder, 0.0f));
                    m_fishOutOfWater->componentCreature->componentLocomotion->setWalkOrder(std::make_shared<Vector2>(m_fishOutOfWater->m_direction));
                }
            }
            break;
        }
    }

    void ComponentFishOutOfWaterBehavior::StateMachine::leave()
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            break;
        case MachineState::Jump:
            m_fishOutOfWater->setIsBend(false);
            break;
        }
    }

    // **************************************



    ComponentFishOutOfWaterBehavior::~ComponentFishOutOfWaterBehavior()
    {
        delete m_stateMachine;
    }

    float ComponentFishOutOfWaterBehavior::getImportanceLevel()
    {
        return m_importanceLevel;
    }
    bool ComponentFishOutOfWaterBehavior::isOutOfWater()
    {
        return componentCreature->componentBody->immersionFactor < 0.33f;
    }
    bool ComponentFishOutOfWaterBehavior::getIsBend()
    {
        return m_isBend;
    }
    void ComponentFishOutOfWaterBehavior::setIsBend(bool isBend)
    {
        if (isBend != m_isBend)
        {
            m_isBend = isBend;
            // 发送数据包 ... 待完成...
        }
    }


    void ComponentFishOutOfWaterBehavior::update(float dt)
    {
        if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.05f * dt)
        {
            m_importanceLevel = GameSingleton::gameRandom->getFloat(1.0f, 2.0f);
        }
        if (isActive())
        {
            m_stateMachine->update(dt);
        }
        else if (m_stateMachine->currentState() !=  MachineState::Inactive)
        {
            m_stateMachine->changeTo(MachineState::Inactive);
        }
    }

    static const std::string componentName = "FishOutOfWaterBehavior";
    const std::string &ComponentFishOutOfWaterBehavior::getName() const
    {
        return componentName;
    }
    const std::string &ComponentFishOutOfWaterBehavior::GetName()
    {
        return componentName;
    }
    void ComponentFishOutOfWaterBehavior::load(const nlohmann::json &jsonData)
    {
        componentCreature = GameSingleton::gameRegistry->get<ComponentCreature *>(entity);

        subsystemTimeOfDay = GameSingleton::singletonPtr->getSingleton<SubsystemTimeOfDay>();

        m_stateMachine = new StateMachine(this);
    }

}
